﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Threading;

namespace eeb_2012_clientserver_server
{
    public class ConnectionHandler
    {
        private StateObject state;
        public bool connected = false;
        private String ipAddress;
        private Int32 port;
        private ManualResetEvent doneDone = new ManualResetEvent(false);
        private ManualResetEvent sendDone = new ManualResetEvent(false);
        private ManualResetEvent receiveDone = new ManualResetEvent(false);

        public static ArrayList conArr = new ArrayList();

        private ArrayList objToSend = null;

        public ConnectionHandler(StateObject stateObj)
        {
            state = stateObj;
            connected = true;
            ipAddress = ((IPEndPoint)state.workSocket.RemoteEndPoint).Address.ToString();
            port = ((IPEndPoint)state.workSocket.RemoteEndPoint).Port;
            ConnectionHandler.conArr.Add(this);

            objToSend = new ArrayList();

            //Console.WriteLine("------------ New Connection Handler created. Processing...");
        }

        public void closeConnection()
        {
            // set connected flag to signal receive/send-threads.
            connected = false;
            // Signal to release receiving thread.
            receiveDone.Set();
            // Signal to release sending thread.
            sendDone.Set();

            // Remove ConnectionHandler from list.
            ConnectionHandler.conArr.Remove(this);

            Console.WriteLine("------------ ConnectionHandler closed: {0}:{1}", getIpString(), getPortInt());
        }

        public static void addData(StateObject state, byte[] buffer)
        {
            foreach (ConnectionHandler chandl in ConnectionHandler.conArr)
            {
                if (!chandl.Equals(state.chandler))
                {
                    chandl.objToSend.Add(buffer);
                    Console.WriteLine("Package added!");
                }
            }
        }


        // **********************
        // Threading
        // ********************
        public void receiveThread()
        {
            while (state.workSocket.Connected && connected)
            {
                receiveDone.Reset();
                Server.Receive(state.workSocket, state);
                receiveDone.WaitOne();
                Thread.Sleep(5);
            }
            Console.WriteLine("RECEIVING THREAD ENDED");
        }

        public void sendThread()
        {
            while (state.workSocket.Connected && connected)
            {
                sendDone.Reset();
                //Console.WriteLine(objToSend.Count);

                ArrayList sendNow = new ArrayList();
                lock (objToSend.SyncRoot)
                {
                    sendNow = (ArrayList)objToSend.Clone();
                    objToSend.Clear();
                }

                while (sendNow.Count > 0)
                {
                    foreach (byte[] data in sendNow)
                    {

                        Server.Send(state.workSocket, data, state);
                        sendDone.WaitOne();
                    }
                    sendNow.Clear();
                }
                Thread.Sleep(5);
            }
            Console.WriteLine("SENDING THREAD ENDED");
        }

        public static Boolean stopAllThreads()
        {
            // Alle Server-Threads stoppen
            ArrayList stopNow = new ArrayList();
            stopNow = (ArrayList)ConnectionHandler.conArr.Clone();

            for (IEnumerator e = stopNow.GetEnumerator(); e.MoveNext(); )
            {
                ConnectionHandler ch = (ConnectionHandler)e.Current;
                ch.closeConnection();
            }
            return true;
        }

        public void setReceiveDone()
        {
            receiveDone.Set();
        }

        public void setSendDone()
        {
            sendDone.Set();
        }

        // **********************
        // Getter/Setter
        // ******************** 
        public String getIpString()
        {
            return ipAddress;
        }

        public Int32 getPortInt()
        {
            return port;
        }

        // **********************
        // Console functions
        // ********************
        public static void printConnectionList()
        {
            if (ConnectionHandler.conArr != null)
            {
                ArrayList connections = ConnectionHandler.conArr;
                if (connections.Count > 0)
                {
                    int i = 1;
                    foreach (ConnectionHandler cHandl in ConnectionHandler.conArr)
                    {
                        Console.WriteLine(" Client {2}: {0}:{1}", cHandl.getIpString(), cHandl.getPortInt(), i);
                        i++;
                    }
                }
                else
                    Console.WriteLine("Sorry, no client connected!");
            }
            else
            {
                Console.WriteLine("Sorry, no client connected!");
            }
        }
    }
}
